#include <iostream>
#include <cmath>

using namespace std;

class Clock {
    public:
        Clock(int newH, int newM, int newS);// 构造函数
        Clock();// 默认构造函数
        void setTime(int newH = 0, int newM = 0, int newS = 0);
        void showTime();
        ~Clock();// 析构函数声明
    
    private:
        int hour, minute, second;
};

// 构造函数实现
Clock::Clock(int newH, int newM, int newS): hour(newH),minute(newM), second(newS) {
    //
}
Clock::Clock(): hour(0), minute(0), second(0) {}// 默认构造函数


// 成员函数实现
void Clock::setTime(int newH, int newM, int newS) {
    hour = newH;
    minute = newM;
    second = newS;
}
void Clock::showTime() {
    cout << hour << ":" << minute << ":" << second;
}



// 类的组合，线段（line）类
class Point { // Point类定义
public:
    Point(int xx = 0, int yy = 0) {
        x = xx;
        y = yy;
    }
    Point(Point &p);
    int getX() {return x;}
    int getY() {return y;}
private:
    int x, y;
};

Point::Point(Point &p) {// 复制构造函数的实现
    x = p.x;
    y = p.y;
    cout << "Calling the copy constructor of Point" << endl;
}

// 类的组合
class Line {// Line 类的定义
public:// 外部接口
    Line(Point xp1, Point xp2);
    Line(Line &l);
    double getLen() {return len;}
private:// 私有数据成员
    Point p1, p2;// Point 类的对象 p1, p2
    double len;
};

// 组合类的构造函数
Line::Line(Point xp1, Point xp2): p1(xp1), p2(xp2) {
    cout << "Calling constructor of line" << endl;
    double x = static_cast<double>(p1.getX() - p2.getX());
    double y = static_cast<double>(p1.getY() - p2.getY());
    len = sqrt(x * x + y * y);
}
Line::Line(Line &l): p1(l.p1), p2(l.p2) {
    // 组合类的复制构造函数
    cout << "Calling the copy constructor of Line" << endl;
    len = l.len;
}


class Fred;// 前向引用声明

class Fred {
    //
};

// 结构体，与C兼容
// 与类的唯一区别：类的缺省访问权限是private，结构体的缺省访问权限是 public
struct Student {
    int num;
    string name;
    char sex;
    int age;
    // protected:
    //     string address;
    // private:
    //     unsigned int cash; 
};


// 联合体
// 成员共用同一组内存单元
// 任何两个成员不会同时有效
union Mark {// 表示成绩的联合体
    char grade;// 等级制的成绩
    bool pass;// 只记是否通过课程的成绩
    int percent;// 百分制的成绩
};


// 枚举类
enum class Type {
    General,
    Light,
    Medium,
    Heavy
};
enum class Side {
    Right,
    Left
};
enum class Thing {
    Wrong,
    Right// 不冲突
};


int i;// i 为全局变量，具有静态生存期
void other() {
    // a, b 为静态局部变量，具有全局寿命，局部可见
    // 只第一次进入函数时被初始化
    static int a = 2;
    static int b;

    int c = 10;// c 为局部变量，具有动态生存期，每次进入函数时都初始化

    a += 2;
    i += 32;
    c += 5;
    cout << "---OTHER---\n";
    cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl;
    b = a;
    
}



class Point2 { // Point 类定义

public:// 外部接口
    Point2(int x = 0, int y = 0): x(x),y(y) {// 构造函数
        // 在构造函数中对 count 累加，所有对象共同维护同一个 count
        count++;
    }
    Point2(Point2 &p) {// 复制构造函数
        x = p.x;
        y = p.y;
        count++;
    }
    ~Point2() {count--;}
    int getX() {return x;}
    int getY() {return y;}
    void showCount() {
        // 输出静态数据成员
        cout << " Object count = " << count << endl;
    }
private:// 私有数据成员
    int x, y;
    static int count;// 静态数据成员声明，用于记录点的个数

};
int Point2::count = 0;// 静态数据成员定义和初始化，使用类名限定

class Point3 { // Point 类定义

public:// 外部接口
    Point3(int x = 0, int y = 0): x(x),y(y) {}
    int getX() {return x;}
    int getY() {return y;}
    // 友元函数
    // 友元函数是在类声明中由关键字friend修饰说明的非成员函数，
    // 在它的函数体中能够通过对象名访问 private 和 protected成员
    // 作用：增加灵活性，使程序员可以在封装和快速性方面做合理选择。
    // 访问对象中的成员必须通过对象名。
    friend float dist(Point3 &a, Point3 &b);
private:// 私有数据成员
    int x, y;

};

// 友元类
// 若一个类为另一个类的友元，则此类的所有成员都能访问对方类的私有成员
// 声明语法：将友元类名在另一个类中使用friend修饰说明
// 类的友元关系是单向的
// 如果声明B类是A类的友元，B类的成员函数就可以访问A类的私有和保护数据，
// 但A类的成员函数却不能访问B类的私有、保护数据
class A {
    friend class B;
public:
    void display() {
        cout << x << endl;
    }
private:
    int x;
};

class B {
public:
    void set(int i);
    void display();
private:
    A a;
};

void B::set(int i) {
    a.x = i;
}
void B::display() {
    a.display();
}


float dist(Point3 &a, Point3 &b) {
    double x = a.x - b.x;
    double y = a.y - b.y;

    return static_cast<float>(sqrt(x*x + y*y));
}


// 常类型
//      常对象：必须进行初始化,不能被更新。
//          const 类名 对象名
//      常成员
//          用const进行修饰的类成员：常数据成员和常函数成员
//      常引用：被引用的对象不能被更新
//          const 类型说明符 &引用名
//      常数组：数组元素不能被更新
//          类型说明符 const 数组名[大小]...
//      常指针：指向常量的指针

// 常对象
//      用const修饰的对象
class A1 {

public:
    A1(int i, int j) {x = i;y = j;}
private:
    int x, y;
};
A1 const a1(3, 4);// a是常对象，不能被更新

// 常成员
//      用const修饰的对象成员
//      常成员函数
//          使用const关键字说明的函数
//          常成员函数不更新对象的数据成员
//          常成员函数说明格式：
//              类型说明符 函数名（参数表）const;
//              这里，const是函数类型的一个组成部分，因此在实现部分也要带const关键字。
//          const关键字可以被用于参与对重载函数的区分
//      通过常对象只能调用它的常成员函数
//      常数据成员
//          使用const说明的数据成员

// 常成员函数
class R {
public:
    R(int r1, int r2): r1(r1), r2(r2) {}
    void print();
    void print() const;
private:
    int r1, r2;
};

void R::print() {
    cout << r1 << ":" << r2 << endl;
}
void R::print() const {
    cout << r1 << ";" << r2 << endl;
}

// 常数据成员
class A2 {
public:
    A2(int i);
    void print();
private:
    const int a;
    static const int b;// 静态常数据成员
};

const int A2::b = 10;
A2::A2(int i): a(i) {}
void A2::print() {
    cout << a << ":" << b << endl;
}


// 常引用
//      如果在声明引用时用const修饰，被声明的引用就是常引用
//      常引用所引用的对象不能被更新
//      如果用常引用做形参，便不会意外地发生对实参的更改。
//      常引用的声明形式如下
//          const 类型说明符 &引用名;


// 常引用作形参
class Point4 {// Point 类定义

public:// 外部接口
    Point4(int x = 0, int y = 0): x(x), y(y) {}
    int getX() {return x;}
    int getY() {return y;}
    friend float dist(const Point4 &p1, const Point4 &p2);
private:// 私有数据成员
    int x, y;

};

float dist(const Point4 &p1, const Point4 &p2) {
    double x = p1.x - p2.x;
    double y = p1.y - p2.y;
    return static_cast<float>(sqrt(x*x + y*y));
}








int main() {






    // const Point4 myP1(1, 1), myP2(4, 5);
    // cout << "The distance is: ";
    // cout << dist(myP1, myP2) << endl;





    // // 建立对象 a 和 b，并以 100 和 0 作为初值，分别调用构造函数
    // // 通过构造函数的初始化列表给对象的常数据成员赋初值
    // A2 a1(100), a2(0);
    // a1.print();
    // a2.print();





    // R a(5, 4);
    // a.print();// 调用 void print()
    // const R b(20, 52);
    // b.print();// 调用 void print() const





    // // 使用友元函数计算两点间的距离
    // Point3 p1(1, 1), p2(4, 5);
    // cout << "The distance is: ";
    // cout << dist(p1, p2) << endl;




    // Point2 a(4, 5);// 定义对象 a，其构造函数会使 count 值增 1
    // cout << "Point A: " << a.getX() << ", " << a.getY();
    // a.showCount();// 输出对象个数

    // Point2 b(a);// 定义对象 b，其构造函数会使 count 增 1
    // cout << "Point B: " << b.getX() << ", " << b.getY();
    // b.showCount();// 输出对象个数




    // static int a;// 静态局部变量，有全局寿命，局部可见
    // int b = -10;// b, c为局部变量，具有动态生存期
    // int c = 0;
    // cout << "---MAIN---\n";
    // cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl;
    // i += 10;
    // other();




    // Side s = Side::Right;
    // Thing w = Thing::Wrong;
    // // cout << (s == w) << endl;// 编译错误，无法直接比较不同枚举类



    // Student stu = {97001, "Lin Lin", 'F', 19};
    // cout << "Num: " << stu.num << endl;



    // Point myp1(1, 1), myp2(4, 5);// 建立Point类的对象
    // Line line(myp1, myp2);// 建立Line类的对象
    // Line line2(line);// 利用复制构造函数建立一个新对象
    // cout << "The length of the line is: ";
    // cout << line.getLen() <<endl;
    // cout << "The length of the line2 is: ";
    // cout << line2.getLen() << endl;


    
    // Clock c2;// 调用无参构造函数

    // Clock c(0, 0, 0);// 自动调用构造函数
    // c.showTime();



    // Clock myClock;
    // myClock.setTime(8, 30, 30);
    // myClock.showTime();


    system("pause");

    return 0;
}